using System;
using System.Collections.Generic;
using System.Numerics;
using TTEngine.Graphics;
using TTEngine.TTMath;
using Silk.NET.OpenGLES;
using TTEngine.Resource;

namespace TTEngine.Graphics
{
    public class IndexTex : ResourceObj
    {
        private uint _width;
        private uint _height;
        private byte[] _data;
        private bool _dirty;
        private Texture2D _texture;

        public uint Width => _width;
        public uint Height => _height;
        public Texture2D Texture => _texture;

        public IndexTex(ResourcePackage package, uint width, uint height)
            : base(package)
        {
            _width = width;
            _height = height;
            _data = new byte[width * height * 4];
            _dirty = false;
            _texture = new Texture2D(package, width, height, TextureType.RGBA_32);
        }

        protected override void OnDestory()
        {
            _texture.DecRef();
            if (_texture.CanDispose)
            {
                _texture.Destory();
            }
        }

        public void MarkDirty()
        {
            _dirty = true;
        }

        public void DropData()
        {
            _data = null;
        }

        public byte[] GetData()
        {
            return _data;
        }

        public void SetIndexLayer1(int x, int y, int posU, int posV)
        {
            if (_data == null)
                _data = new byte[_width * _height * 4];

            _data[(y * _width + x) * 4 + 0] = (byte)posU;
            _data[(y * _width + x) * 4 + 1] = (byte)posV;
            _dirty = true;
        }

        public void SetIndexLayer2(int x, int y, int posU, int posV)
        {
            if (_data == null)
                _data = new byte[_width * _height * 4];

            _data[(y * _width + x) * 4 + 2] = (byte)posU;
            _data[(y * _width + x) * 4 + 3] = (byte)posV;
            _dirty = true;
        }

        public void FillIndexLayer1(TileLayer tiledlayer)
        {
            var random = new Random();
            for (int j = 0; j < _height; j++)
            {
                for (int i = 0; i < _width; i++)
                {
                    int r = (int)(random.NextDouble() * 100 + 0.5);
                    int k = r - 97;
                    if (k < 0) k = 0;
                    if (k > 3) k = 3;
                    var t = tiledlayer.tiled[k];
                    SetIndexLayer1(i, j, t.posU, t.posV);
                }
            }
        }

        public void FillIndexLayer2WithData(TileLayer tiledlayer, byte[] fillData)
        {
            // 每四格一样，避免奇怪的格子出现
            for (int j = 0; j < _height; j += 2)
            {
                for (int i = 0; i < _width; i += 2)
                {
                    byte c0 = fillData[j * _width + i];
                    byte c1 = fillData[j * _width + i + 1];
                    byte c2 = fillData[(j + 1) * _width + i];
                    byte c3 = fillData[(j + 1) * _width + i + 1];
                    byte sum = (byte)(c0 + c1 + c2 + c3);
                    byte v = (byte)(sum >= 2 ? 1 : 0);
                    fillData[j * _width + i] = v;
                    fillData[j * _width + i + 1] = v;
                    fillData[(j + 1) * _width + i] = v;
                    fillData[(j + 1) * _width + i + 1] = v;
                }
            }

            for (int j = 0; j < _height; j++)
            {
                for (int i = 0; i < _width; i++)
                {
                    byte c0 = 0, c1 = 0, c2 = 0;
                    if (j > 0)
                    {
                        if (i > 0)
                            c0 = fillData[(j - 1) * _width + i - 1];
                        c1 = fillData[(j - 1) * _width + i];
                        if (i < _width - 1)
                            c2 = fillData[(j - 1) * _width + i + 1];
                    }

                    byte c3 = 0, c4 = 0, c5 = 0;
                    {
                        if (i > 0)
                            c3 = fillData[j * _width + i - 1];
                        c4 = fillData[j * _width + i];
                        if (i < _width - 1)
                            c5 = fillData[j * _width + i + 1];
                    }

                    byte c6 = 0, c7 = 0, c8 = 0;
                    if (j < _height - 1)
                    {
                        if (i > 0)
                            c6 = fillData[(j + 1) * _width + i - 1];
                        c7 = fillData[(j + 1) * _width + i];
                        if (i < _width - 1)
                            c8 = fillData[(j + 1) * _width + i + 1];
                    }

                    if (c4 > 0)
                    {
                        int crosscount = 0;
                        if (c1 > 0) crosscount++;
                        if (c3 > 0) crosscount++;
                        if (c5 > 0) crosscount++;
                        if (c7 > 0) crosscount++;

                        if (crosscount == 0)
                        {
                            SetIndexLayer2(i, j, tiledlayer.smallpot.posU, tiledlayer.smallpot.posV);
                        }
                        else if (crosscount == 1)
                        {
                            // error
                        }
                        else if (crosscount == 2)
                        {
                            if (c1 == 0 && c3 == 0)
                                SetIndexLayer2(i, j, tiledlayer.outCorner[0].posU, tiledlayer.outCorner[0].posV);
                            if (c1 == 0 && c5 == 0)
                                SetIndexLayer2(i, j, tiledlayer.outCorner[2].posU, tiledlayer.outCorner[2].posV);
                            if (c7 == 0 && c3 == 0)
                                SetIndexLayer2(i, j, tiledlayer.outCorner[6].posU, tiledlayer.outCorner[6].posV);
                            if (c7 == 0 && c5 == 0)
                                SetIndexLayer2(i, j, tiledlayer.outCorner[8].posU, tiledlayer.outCorner[8].posV);
                        }
                        else if (crosscount == 3)
                        {
                            // 边
                            if (c1 == 0)
                                SetIndexLayer2(i, j, tiledlayer.outCorner[1].posU, tiledlayer.outCorner[1].posV);
                            if (c3 == 0)
                                SetIndexLayer2(i, j, tiledlayer.outCorner[3].posU, tiledlayer.outCorner[3].posV);
                            if (c5 == 0)
                                SetIndexLayer2(i, j, tiledlayer.outCorner[5].posU, tiledlayer.outCorner[5].posV);
                            if (c7 == 0)
                                SetIndexLayer2(i, j, tiledlayer.outCorner[7].posU, tiledlayer.outCorner[7].posV);
                        }
                        else if (crosscount == 4)
                        {
                            int corcount = 0;
                            if (c0 > 0) corcount++;
                            if (c2 > 0) corcount++;
                            if (c6 > 0) corcount++;
                            if (c8 > 0) corcount++;

                            if (corcount == 3) // 内角
                            {
                                if (c0 == 0)
                                    SetIndexLayer2(i, j, tiledlayer.innerCorner[3].posU, tiledlayer.innerCorner[3].posV);
                                if (c2 == 0)
                                    SetIndexLayer2(i, j, tiledlayer.innerCorner[2].posU, tiledlayer.innerCorner[2].posV);
                                if (c6 == 0)
                                    SetIndexLayer2(i, j, tiledlayer.innerCorner[1].posU, tiledlayer.innerCorner[1].posV);
                                if (c8 == 0)
                                    SetIndexLayer2(i, j, tiledlayer.innerCorner[0].posU, tiledlayer.innerCorner[0].posV);
                            }
                            else
                            {
                                var random = new Random();
                                int r = (int)(random.NextDouble() * 100 + 0.5);
                                int k = r - 97;
                                if (k < 0) k = 0;
                                if (k > 3) k = 3;
                                var t = tiledlayer.tiled[k];
                                SetIndexLayer2(i, j, t.posU, t.posV);
                            }
                        }
                    }
                    else
                    {
                        SetIndexLayer2(i, j, 0, 0);
                    }
                }
            }
        }

        public void Apply()
        {
            if (!_dirty)
                return;

            if (_data == null)
                throw new Exception("no data on IndexTex");

            var imageData = new ImageData((int)_width, (int)_height, ImageFormat.RGBA);
            imageData.SetData(_data);
            _texture.UploadImageData(0, 0, _width, _height, imageData);
            _dirty = false;
        }
    }
} 